package io.renren.modules.file.controller;

import io.renren.common.annotation.SysLog;
import io.renren.common.utils.FileUtil;
import io.renren.common.utils.R;


import io.renren.modules.file.entity.BigFileEntity;
import io.renren.modules.file.entity.FileChunkEntity;
import io.renren.modules.file.service.FileService;
import io.renren.modules.project.service.FileVoService;
import io.renren.modules.file.vo.FileVoEntity;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@RestController
@RequestMapping("file/file")
public class FileController {

    @Value("${spring.file.uploadFolder}")
    private String uploadFolder;

    @Autowired
    private FileService fileService;

    /**
     * 文件列表
     */
    @RequestMapping("/list")
    @RequiresPermissions("file:file:list")
    public R list(@RequestParam Map<String, Object> params) {
        try {
            boolean isSearch = Boolean.valueOf(params.get("isSearch").toString());
            List<FileVoEntity> fList = new ArrayList<>();
            if (isSearch) {
                fList = fileService.getListBySearchVal(uploadFolder,params);
            } else {
                fList = fileService.getListByPath(uploadFolder,params);
            }

//        // 查看当前磁盘空间
//        FileSpaceVoEntity spaceVo = new FileSpaceVoEntity();
//        spaceVo.setFreeSpace(dir.getFreeSpace());
//        spaceVo.setTotalSpace(dir.getTotalSpace());
//        spaceVo.setUsableSpace(FileUtils.sizeOfDirectory(dir));
            return R.ok().put("list", fList).put("spaceVo","");
        } catch (Exception ex) {
            return R.error(ex.getMessage());
        }


    }

    /**
     * 新建文件
     */
    @SysLog("新建文件")
    @RequestMapping("/save")
    @RequiresPermissions("file:file:save")
    public R save(@RequestBody FileVoEntity voEntity) {
        String filePath = voEntity.getFilePath();
        String newName = voEntity.getNewName();
        if ( new File(uploadFolder + filePath + "/" + newName).exists()) {
            return R.error("该文件已存在，请重新创建命名！");
        } else {
            FileUtil.createDir(uploadFolder + filePath + "/" + newName);
            return R.ok();
        }
    }

    /**
     * 更改文件
     */
    @SysLog("更改文件")
    @RequestMapping("/update")
    @RequiresPermissions("file:file:update")
    public R update(@RequestBody FileVoEntity voEntity) {
        String path = voEntity.getFilePath();
        String oldName = voEntity.getOldName();
        String newName = voEntity.getNewName();
        File oldFile = new File(uploadFolder + path + "/" + oldName);
        File newFile = new File(uploadFolder + path + "/" + newName);
        if ( oldFile.exists()) {
            if (newFile.exists()) {
                return R.error("文件名重复，请重新命名！");
            }
            oldFile.renameTo(newFile);
            return R.ok();
        } else {
            return R.error("该文件不存在，请刷新重试！");
        }
    }


    /**
     * 删除文件
     */
    @SysLog("删除文件")
    @RequestMapping("/delete")
    @RequiresPermissions("file:file:delete")
    public R delete(@RequestBody FileVoEntity voEntity) {
        try {
            String path = voEntity.getFilePath();
            FileUtil.deleteDirOrFile(new File(uploadFolder + path + "/" + voEntity.getFileName()));
        }catch (Exception ex) {
            return R.error("删除文件出错！");
        }
        return R.ok("删除文件成功！");
    }

    @PostMapping("/chunkUpload")
//    @RequiresPermissions("file:file:save")
    public void fileChunkUpload(@ModelAttribute FileChunkEntity param, HttpServletRequest request, HttpServletResponse response){
        // response.setStatus对接前端插件
        //        200, 201, 202: 当前块上传成功，不需要重传。
        //        404, 415. 500, 501: 当前块上传失败，会取消整个文件上传。
        //        其他状态码: 出错了，但是会自动重试上传。
        try {
            /**
             * 判断前端Form表单格式是否支持文件上传
             */
            boolean isMultipart = ServletFileUpload.isMultipartContent(request);
            if(!isMultipart){
                //这里是我向前端发送数据的代码，可理解为 return 数据; 具体的就不贴了
                System.out.println("不支持的表单格式");
                response.setStatus(404);
                response.getOutputStream().write("不支持的表单格式".getBytes());
            }else {
                param.setTaskId(param.getIdentifier());
                fileService.chunkUploadByteBuffer(param,uploadFolder + param.getRelativePath());//service层
                response.setStatus(200);
                response.getWriter().print("上传成功");
            }
            response.getWriter().flush();
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("上传文件失败");
            response.setStatus(415);
        }
    }

    @RequestMapping("/download")
    @RequiresPermissions("file:file:download")
    public void download(HttpServletResponse response, @RequestParam Map<String, Object> params) {
        try {
            String path = uploadFolder  + (String)params.get("path") ;
            File file = new File(path);
            if (file.isDirectory()) {
                // ZipOutputStream类：完成文件或文件夹的压缩
                BufferedInputStream bufferedInputStream = null;
                ZipOutputStream zipOutputStream = null;
                OutputStream outputStream = response.getOutputStream();;
                zipOutputStream = new ZipOutputStream(outputStream);

                File fItem = new File(path);
                if (fItem.exists()) {
                    // 创建ZIP实体，并添加进压缩包 (这里可能会有重名问题，需要加个标识)
                    ZipEntry zipEntry = new ZipEntry(fItem.getName());
                    zipOutputStream.putNextEntry(zipEntry);
                    // 读取待压缩的文件并写进压缩包里
                    bufferedInputStream = new BufferedInputStream(new FileInputStream(file), 1024 * 10);
                    int len;
                    // 定义每次读取的字节数组
                    byte[] buffer = new byte[1024];
                    while ((len = bufferedInputStream.read(buffer)) != -1) {
                        zipOutputStream.write(buffer, 0, len);
                    }
                }

                zipOutputStream.flush();
                zipOutputStream.close();
                response.reset();
                response.addHeader("Access-Control-Allow-Origin" , "*");
                response.setHeader("Access-Control-Allow-Credentials" ,"false");
                response.setHeader("Content-Disposition", "attachment; filename=\"map.zip\"");
                response.addHeader("Content-Length", "" );
                response.setContentType("application/octet-stream; charset=UTF-8");

            }else {
                FileUtil.downloadFiles(response,path);
            }
        } catch (Exception ex) {
//            return R.error(ex.getMessage());
        }
//        return R.ok();
    }
}
